package com.ruoyi.quartz.task;

import com.google.common.util.concurrent.*;
import com.ruoyi.bizsys.domain.BatchJobMonitoring;
import com.ruoyi.bizsys.domain.CreditAccount;
import com.ruoyi.bizsys.service.ICreditAccountService;
import com.ruoyi.business.service.IBRepaymentService;
import com.ruoyi.business.service.IBatchDateJobService;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.RspEnmu;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.quartz.thread.BatchRepaymentThread;
import com.ruoyi.system.service.ISysConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 批量代扣任务
 *
 * @author ruoyi
 */
@Slf4j
@Component("batchRepayment")
public class BatchRepayment {

    @Autowired
    IBatchDateJobService batchDateJobService;

    @Autowired
    IBRepaymentService repaymentService;

    @Autowired
    ICreditAccountService iCreditAccountService;

    @Autowired
    RedisCache redisCache;

    @Autowired
    ISysConfigService iSysConfigService;

    @Autowired
    RedisTemplate redisTemplate;

    public void runBatch(Integer type) {
        log.info("批量代扣任务 Start>>>>>>>>>>");
        saveRedis(type);
        //获取系统最近跑批
//        BatchJobMonitoring BatchJobMonitoring = batchDateJobService.getBatchDateRecord();
//        if (null == BatchJobMonitoring) {
//            log.info("最近跑批记录为null");
//            throw new BusinessException(RspEnmu.SYSTEM_SYSDATA_EXCEPTION);
//        }

//        log.info("最近跑批日为{}", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, BatchJobMonitoring.getBatchDate()));
//        Date batchDate = BatchJobMonitoring.getBatchDate();
//        String batchDateStr = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, batchDate);
//
//        //当天日期
//        String nowDateStr = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, new Date());
//        if (!batchDateStr.equals(nowDateStr)) {
//            log.info("当日跑批未执行成功，无法执行批量代扣");
//            throw new BusinessException(RspEnmu.SYSTEM_SYSDATA_EXCEPTION);
//        }

        //当天日期
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        //将时分秒置0
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        //开始跑批
        Date nowDate = calendar.getTime();

        //查询批量代扣涉及的用户数
        //int accountCount = repaymentService.getBatchRepaymentCustCount();
        //List<CreditAccount> accountList = repaymentService.getBatchRepaymentAccount();
        CreditAccount creditAccount = new CreditAccount();
        creditAccount.setState("1");
        creditAccount.setOnLoan("1");
        List<CreditAccount> accountList = iCreditAccountService.selectCreditAccountList(creditAccount);
        int accountCount = accountList.size();
        if (accountCount > 0) {
            String redisName = "cardBatchSplitDebit:"+DateUtils.dateTime(nowDate);

            int threadStep = 20;//每个线程执行的客户数
            //需要multiple个线程来执行
            int threadCount = accountCount / threadStep;
            if (threadCount * threadStep != accountCount) {
                threadCount++;
            }
            //线程计数器
            final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
            //线程池大小
            int poolSize = 5;

            ExecutorService executorService = Executors.newFixedThreadPool(poolSize);
            ListeningExecutorService listeningExecutorService = MoreExecutors.listeningDecorator(executorService);

            int threadAccountCount = 0;
            while (threadAccountCount < accountCount) {
                //分页取数startNum
                int startLimit = threadAccountCount;

                threadAccountCount += threadStep;

                if(threadAccountCount>accountCount){
                    threadAccountCount = accountCount;
                }

                String redisName1 = redisName+":"+startLimit+"-"+threadAccountCount;
                List<CreditAccount> accountList1 = accountList.subList(startLimit,threadAccountCount);
                redisCache.setCacheList(redisName1,accountList1);
                redisCache.expire(redisName1,23,TimeUnit.HOURS);

                BatchRepaymentThread thread = new BatchRepaymentThread("[cardBatchSplitDebit-" + startLimit + "]",
                        nowDate, redisName1, repaymentService,redisCache,type);
                ListenableFuture listenableFuture = listeningExecutorService.submit(thread);

                Futures.addCallback(listenableFuture, new FutureCallback<String>() {
                    @Override
                    public void onSuccess(String result) {
                        countDownLatch.countDown();
                        log.info("[" + this.getClass().getName() + "]线程处理结果：" + result);
                    }

                    @Override
                    public void onFailure(Throwable throwable) {
                        countDownLatch.countDown();
                        log.info("[" + this.getClass().getName() + "]线程处理出错：" + throwable);
                    }
                });
            }

            try {
                countDownLatch.await(3 * 60, TimeUnit.MINUTES);//超过3个小时放弃
            } catch (InterruptedException e) {
                log.error("当日批量代扣执行失败，为正常结束", e);
            }
        } else {
            log.info("批量代扣任务没有记录需要执行");
        }

        clearRedis(type);
        log.info("批量代扣任务 End>>>>>>>>>>");
    }

    public void runBatchByCustNo(String custNo){
        log.info("批量代扣任务runBatchByCustNo Start>>>>>>>>>>");
        saveRedis(1);

        CreditAccount creditAccount = new CreditAccount();
        creditAccount.setState("1");
        creditAccount.setOnLoan("1");
        creditAccount.setCustNo(custNo);
        List<CreditAccount> accountList = iCreditAccountService.selectCreditAccountList(creditAccount);

        if(accountList.size()>0){
            repaymentService.doBatchRepaymentByAccount(accountList.get(0),1);
        }
        clearRedis(1);
        log.info("批量代扣任务runBatchByCustNo End>>>>>>>>>>");
    }

    public void saveRedis(int type){
        String minDdaysKey;
        String maxDaysKey;
        String subtractDaysKey;
        String surplusDaysKey;
        if(type==1){
            minDdaysKey = "withhold_am_min_days";
            maxDaysKey = "withhold_am_max_days";
            subtractDaysKey = "withhold_am_subtract_days";
            surplusDaysKey = "withhold_am_surplus_days";
        }else if(type==2){
            minDdaysKey = "withhold_pm_min_days";
            maxDaysKey = "withhold_pm_max_days";
            subtractDaysKey = "withhold_pm_subtract_days";
            surplusDaysKey = "withhold_pm_surplus_days";
        }else{
            minDdaysKey = "withhold_all_min_days";
            maxDaysKey = "withhold_all_max_days";
            subtractDaysKey = "withhold_all_subtract_days";
            surplusDaysKey = "withhold_all_surplus_days";
        }

        String minDdaysStr = iSysConfigService.selectConfigByKey(minDdaysKey);
        Integer minDdays = minDdaysStr==null?null:Integer.parseInt(minDdaysStr);
        redisCache.setCacheObject("cardBatchSplitDebit:"+type+":minDdays",minDdays);
        String maxDaysStr = iSysConfigService.selectConfigByKey(maxDaysKey);
        Integer maxDays = maxDaysStr==null?null:Integer.parseInt(maxDaysStr);
        redisCache.setCacheObject("cardBatchSplitDebit:"+type+":maxDays",maxDays);
        String subtractDaysStr = iSysConfigService.selectConfigByKey(subtractDaysKey);
        Integer subtractDays = subtractDaysStr==null?null:Integer.parseInt(subtractDaysStr);
        redisCache.setCacheObject("cardBatchSplitDebit:"+type+":subtractDays",subtractDays);
        String surplusDaysStr = iSysConfigService.selectConfigByKey(surplusDaysKey);
        Integer surplusDays = surplusDaysStr==null?null:Integer.parseInt(surplusDaysStr);
        redisCache.setCacheObject("cardBatchSplitDebit:"+type+":surplusDays",surplusDays);
    }

    public void clearRedis(int type){
        redisTemplate.delete(redisTemplate.keys("cardBatchSplitDebit:"+type+"*"));
    }
}
